package top.callback.inf.beautyleaf.common;

import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import top.callback.inf.beautyleaf.exception.BeautyLeafException;

import java.io.InputStream;
import java.lang.reflect.Method;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

/**
 * 配置信息类，从 classpath:beauty-leaf.properties 加载配置信息。
 *
 * @author Pengyu Gan
 * CreateDate 2021/3/23
 */
@Data
@Slf4j
public class Config {

    private String jdbcDriver;

    private String jdbcUrl;

    private String jdbcUsername;

    private String jdbcPassword;

    /**
     * 确保缓存和数据库的标签数据一致 定时任务的执行周期
     */
    private Integer keepConsistencePeriod = 30;

    /**
     * 加载另一个号码段的阈值
     */
    private Double loadSegmentThreshold = 0.9;

    /**
     * 当前 BeautyLeaf 节点的名称
     */
    private String instanceName;

    /**
     * 当前 BeautyLeaf 实例的端口，这个端口并不是一个网络意义的端口，只是为了一台机器启动多个实例时在 ZK 里区分不同的 PATH
     */
    private Integer instancePort = 931026;

    /**
     * 雪花算法起始时间戳，默认为 2021-01-01 00:00:00
     */
    private Long instanceTwepoch = 1609430400000L;

    /**
     * Zookeeper 连接地址，多个地址以逗号分隔
     */
    private String zookeeperAddress;

    /**
     * Zookeeper 连接超时毫秒数
     */
    private Integer zookeeperConnectionTimeout = 10000;

    /**
     * Zookeeper 会话超时毫秒数
     */
    private Integer zookeeperSessionTimeout = 6000;

    private static Config instance = null;

    private Config() {}

    /**
     * 从配置文件加载配置信息
     * @return 配置信息
     */
    public static Config load() {
        if (instance != null) {
            return instance;
        }
        Config config = new Config();
        return loadConfig(config);
    }

    private static Config loadConfig(Config config) {
        try (InputStream inputStream = config.getClass().getClassLoader().getResourceAsStream("beauty-leaf.properties")) {
            // 加载配置文件
            Properties properties = new Properties();
            properties.load(inputStream);
            // 配置项名称枚举
            Enumeration<String> enumeration = (Enumeration<String>) properties.propertyNames();
            Map<String, String> propertyMap = new HashMap<>();
            // 迭代配置项名称
            while (enumeration.hasMoreElements()) {
                // 配置项名称
                String key = enumeration.nextElement();
                // 配置值
                String value = properties.getProperty(key);
                // 使用点号拆分配置项名称
                String[] parts = key.split("\\.");
                StringBuilder propertyNameBuilder = new StringBuilder();
                // 将配置项名称的每个部分首字母大写
                for (String part : parts) {
                    propertyNameBuilder.append(part.substring(0, 1).toUpperCase().concat(part.substring(1)));
                }
                String propertyName = propertyNameBuilder.toString();
                // 没有点号分割并且首字母大写的配置项名称 与 配置值 的映射
                propertyMap.put(propertyName, value);
            }
            // 迭代 Config 的所有方法
            Method[] methods = Config.class.getMethods();
            for (Method method : methods) {
                String methodName = method.getName();
                // 找到 set 方法
                if (methodName.startsWith("set")) {
                    // 拿到 set 方法对应属性的名称
                    String matchedPropertyName = methodName.substring(3);
                    // 从映射中拿到配置值
                    String value = propertyMap.get(matchedPropertyName);
                    if (null == value) {
                        log.warn("属性 {} 的配置值为空", matchedPropertyName);
                    }
                    Class<?>[] methodParameterTypes = method.getParameterTypes();
                    Class<?> parameterType = methodParameterTypes[0];
                    Object finalValue = value;
                    // 大部分情况下配置值的类型都是字符串，所以没有必要做很多无效的判断
                    if (!parameterType.equals(String.class)) {
                        if (parameterType.equals(Integer.class)) {
                            finalValue = Integer.parseInt(value);
                        }
                        if (parameterType.equals(Long.class)) {
                            finalValue = Long.parseLong(value);
                        }
                        if (parameterType.equals(Byte.class)) {
                            finalValue = Byte.parseByte(value);
                        }
                        if (parameterType.equals(Short.class)) {
                            finalValue = Short.parseShort(value);
                        }
                        if (parameterType.equals(Boolean.class)) {
                            finalValue = Boolean.parseBoolean(value);
                        }
                        if (parameterType.equals(Float.class)) {
                            finalValue = Float.parseFloat(value);
                        }
                        if (parameterType.equals(Double.class)) {
                            finalValue = Double.parseDouble(value);
                        }
                    }
                    // 设置值
                    method.invoke(config, finalValue);
                }
            }
            instance = config;
            return config;
        } catch (Exception e) {
            log.error("BeautyLeaf 配置信息初始化失败", e);
            throw new BeautyLeafException("BeautyLeaf 配置信息初始化失败", e);
        }
    }

}
